package com.house365.core.util.lbs;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

import org.apache.http.entity.StringEntity;

import android.app.Activity;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.house365.core.application.BaseApplication;
import com.house365.core.application.BaseApplicationWithMapService;
import com.house365.core.constant.CorePreferences;
import com.house365.core.json.JSONArray;
import com.house365.core.json.JSONObject;

public class MyLocation {
	private LocationManager googleLocationManager;
	private LocationClient mLocationClient;
	private Location location;
	private final int DEVIANTLAT = 0;
	private final int DEVIANTLNG = 0;

	private boolean isGpsEnabled;
	private boolean isNetWorkEnabled;
	private Context context;
	private String googleUrl = "http://www.google.com/loc/json";

	public MyLocation(Context context) {
		this.context = context;
	}

	public static final int LOCATION_GOOGLE = 1;
	public static final int LOCATION_BAIDU = 2;
	public static final int LOCATION_BASESTATION = 4;

	public static final String LOACTION_TYPE_BAIDU="bd09ll";
	public static final String LOACTION_TYPE_COMMON="gcj02";
	/**
	 * ��ȡ��ַͨ�÷���
	 * 
	 * @param locationType
	 *            ��LOCATION_GOOGLE | LOCATION_BAIDU|LOCATION_BASESTATION
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("百度地图api提供了新的定位接口，速度更快，建议使用百度定位api")
	public Location getLocation(int locationType) {
		return getLocation(locationType, false);
	}
	
	public Location getLocation(int locationType, boolean attachAddrInfoForBaiDu) {
		if ((locationType & LOCATION_GOOGLE) == LOCATION_GOOGLE) {
			getLocationByGoogleAPI(0);
			if (location != null) {
				return location;
			}
		}
		if ((locationType & LOCATION_BAIDU) == LOCATION_BAIDU) {
			getLocationByBaiduLocApi(true, 0, attachAddrInfoForBaiDu);
			if (location != null) {
				return location;
			}
		}
		if ((locationType & LOCATION_BASESTATION) == LOCATION_BASESTATION) {
			getLocationByBaseStation();
			if (location != null) {
				return location;
			}
		}
		return null;
	}
	
	@Deprecated
	@SuppressWarnings("百度地图api提供了新的定位接口，速度更快，建议使用百度定位api")
	public void getAsyncLocation(final int locationType,
			final LocationCallBack locationCallBack) {
		getAsyncLocation(locationType, locationCallBack, false);
	}
	
	public void getAsyncLocation(final int locationType,
			final LocationCallBack locationCallBack, boolean attachAddrInfoForBaiDu) {
		new Thread() {
			public void run() {
				location = null;
				if ((locationType & LOCATION_GOOGLE) == LOCATION_GOOGLE
						&& location == null) {
					getLocationByGoogleAPI(0);
				}
				if ((locationType & LOCATION_BAIDU) == LOCATION_BAIDU
						&& location == null) {
					getLocationByBaiduLocApi(true,0);
				}
				if ((locationType & LOCATION_BASESTATION) == LOCATION_BASESTATION
						&& location == null) {
					getLocationByBaseStation();
				}
				locationCallBack.onResult(location);
			};
		}.start();
	}


	/**
	 * �Ƴ��ַ����ͨ�÷���
	 * 
	 * @param locationType
	 */
	@Deprecated
	@SuppressWarnings("百度地图api提供了新的定位接口，速度更快，建议使用百度定位api")
	public void removeLocationUpdate(int locationType) {
		if ((locationType & LOCATION_GOOGLE) == 1) {
			removeGoogleLocationUpdates();
		}
		if ((locationType & LOCATION_BAIDU) == 1) {
//			removeBaiduLocationUpdate();
		}
		if ((locationType & LOCATION_BASESTATION) == 1) {
			// do nothing
		}
	}

	/******************* google��ͼ��ַ���� *********************************/
	/**
	 * ��ȡgoogle��ַ������
	 * 
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("百度地图api提供了新的定位接口，速度更快，建议使用百度定位api")
	private LocationManager getGoogleLocationManager() {
		if (googleLocationManager == null) {
			googleLocationManager = (LocationManager) context
					.getSystemService(Context.LOCATION_SERVICE);
		}
		return googleLocationManager;
	}

	/**
	 * ��ȡ��ַ
	 * 
	 * @return
	 */
	public Location getLocationByGoogleAPI(long duration) {
		if(duration <=0){
			duration= 10000 ;
		}
		location = null;
		isGpsEnabled = getGoogleLocationManager().isProviderEnabled(
				LocationManager.GPS_PROVIDER);
		isNetWorkEnabled = getGoogleLocationManager().isProviderEnabled(
				LocationManager.NETWORK_PROVIDER);
		boolean isRegGPSListener = false, isRegNetworkListener = false;
		long start = System.currentTimeMillis();
		while (System.currentTimeMillis() - start < duration && location == null) {

			if (isGpsEnabled) {
				if (!isRegGPSListener) {
					getGoogleLocationManager().requestLocationUpdates(
							LocationManager.GPS_PROVIDER, 1000, 0,
							googleLocationListener);
					isRegGPSListener = true;
				}

				location = getGoogleLocationManager().getLastKnownLocation(
						LocationManager.GPS_PROVIDER);
			}
			if (location == null && isNetWorkEnabled) {
				if (!isRegNetworkListener) {
					getGoogleLocationManager().requestLocationUpdates(
							LocationManager.NETWORK_PROVIDER, 1000, 0,
							googleLocationListener);
					isRegNetworkListener = true;
				}
				location = getGoogleLocationManager().getLastKnownLocation(
						LocationManager.NETWORK_PROVIDER);
			}
		}
		return location;
	}

	public void removeGoogleLocationUpdates() {
		try {
			getGoogleLocationManager().removeUpdates(googleLocationListener);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * λ�ñ䶯����
	 * */
	private LocationListener googleLocationListener = new LocationListener() {
		public void onLocationChanged(Location loc) {
			if (location != null) {
				CorePreferences.DEBUG("Location changed:Lat:"
						+ location.getLatitude() + " Lng:"
						+ location.getLongitude());
			}
		}

		public void onProviderDisabled(String provider) {
		}

		public void onProviderEnabled(String provider) {
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};

	/************************* ��վ��λ��������ʹ�ã���Ϊ���ںܶ����磨jͨ3G���ƶ�3G������֧�� *****************************************************/
	/**
	 * ͨ���վ��λ
	 * 
	 * @return
	 */
	@Deprecated
	@SuppressWarnings("百度地图api提供了新的定位接口，速度更快，建议使用百度定位api")
	public Location getLocationByBaseStation() {
		location = null;
		TelephonyManager tm = (TelephonyManager) this.context
				.getSystemService(Context.TELEPHONY_SERVICE);
		int type = tm.getNetworkType();
		// ���й��ƶ���2G��EGDE��jͨ��2GΪGPRS�����ŵ�2GΪCDMA�����ŵ�3GΪEVDO
		// String OperatorName = tm.getNetworkOperatorName();
		ArrayList<CellIDInfo> cellIDInfos = new ArrayList<CellIDInfo>();
		// �й����ΪCTC
		// NETWORK_TYPE_EVDO_A���й����3G��getNetworkType
		// NETWORK_TYPE_CDMA����2G��CDMA
		if (type == TelephonyManager.NETWORK_TYPE_EVDO_A
				|| type == TelephonyManager.NETWORK_TYPE_CDMA
				|| type == TelephonyManager.NETWORK_TYPE_1xRTT) {
			CdmaCellLocation location = (CdmaCellLocation) tm.getCellLocation();
			int cellIDs = location.getBaseStationId();
			int networkID = location.getNetworkId();
			StringBuilder nsb = new StringBuilder();
			nsb.append(location.getSystemId());
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = networkID; // ok
			info.mobileNetworkCode = nsb.toString();
			info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			info.radioType = "cdma";
			cellIDInfos.add(info);
		}
		// �ƶ�2G�� + CMCC + 2
		// type = NETWORK_TYPE_EDGE
		else if (type == TelephonyManager.NETWORK_TYPE_EDGE) {
			GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
			int cellIDs = location.getCid();
			int lac = location.getLac();
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = lac;
			info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			info.mobileNetworkCode = tm.getNetworkOperator().substring(3, 5);
			info.radioType = "gsm";
			cellIDInfos.add(info);
		}
		// jͨ��2G������� China Unicom 1 NETWORK_TYPE_GPRS
		else if (type == TelephonyManager.NETWORK_TYPE_GPRS
				|| type == TelephonyManager.NETWORK_TYPE_HSDPA
				|| type == TelephonyManager.NETWORK_TYPE_HSPA) {
			GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
			int cellIDs = location.getCid();
			int lac = location.getLac();
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = lac;
			// ������ԣ���ȡjͨ�������}�б���ȥ��������ִ��󣬴�������ΪJSON Parsing
			// Error

			// info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			// info.mobileNetworkCode = tm.getNetworkOperator().substring(3, 5);
			info.radioType = "gsm";
			cellIDInfos.add(info);
		} else if (type == TelephonyManager.NETWORK_TYPE_UMTS) {
			GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
			int cellIDs = location.getCid();
			int lac = location.getLac();
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = lac;
			//
			// info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			// info.mobileNetworkCode = tm.getNetworkOperator().substring(3, 5);
			info.radioType = "gsm";
			cellIDInfos.add(info);
		} else {
			GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
			int cellIDs = location.getCid();
			int lac = location.getLac();
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = lac;
			// ������ԣ���ȡjͨ�������}�б���ȥ��������ִ��󣬴�������ΪJSON Parsing
			// Error

			// info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			// info.mobileNetworkCode = tm.getNetworkOperator().substring(3, 5);
			info.radioType = "gsm";
			cellIDInfos.add(info);
		}
		location = callGear(cellIDInfos);
		return location;
	}

	private Location callGear(ArrayList<CellIDInfo> cellID) {
		if (cellID == null)
			return null;

		JSONObject holder = new JSONObject();
		try {
			holder.put("version", "1.1.0");
			holder.put("host", "maps.google.com");
			holder.put("request_address", true);
			if ("460".equals(cellID.get(0).mobileCountryCode)) {
				holder.put("address_language", "zh_CN");
			} else {
				holder.put("address_language", "en_US");
			}
			JSONObject data, current_data;
			JSONArray array = new JSONArray();
			current_data = new JSONObject();
			current_data.put("cell_id", cellID.get(0).cellId);
			current_data.put("location_area_code",
					cellID.get(0).locationAreaCode);
			if (!cellID.get(0).radioType.equals("gsm")) {
				current_data.put("mobile_country_code",
						cellID.get(0).mobileCountryCode);
				current_data.put("mobile_network_code",
						cellID.get(0).mobileNetworkCode);
				current_data.put("age", 0);
			}

			array.put(current_data);
			holder.put("cell_towers", array);
			StringEntity se = new StringEntity(holder.toString());
			CorePreferences.DEBUG(holder.toString());
			Log.e("Location send", holder.toString());
			String sb = ((BaseApplication) ((Activity) context)
					.getApplication()).getApi().post(googleUrl, se);
			if (sb.length() <= 1) {
				return null;
			}
			data = new JSONObject(sb.toString());
			data = (JSONObject) data.get("location");

			Location loc = new Location(LocationManager.NETWORK_PROVIDER);
			loc.setLatitude((Double) data.get("latitude"));
			loc.setLongitude((Double) data.get("longitude"));
			loc.setAccuracy(Float.parseFloat(data.get("accuracy").toString()));
			loc.setTime(GetUTCTime());
			return loc;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private long GetUTCTime() {
		Calendar cal = Calendar.getInstance(Locale.CHINA);
		int zoneOffset = cal.get(java.util.Calendar.ZONE_OFFSET);
		int dstOffset = cal.get(java.util.Calendar.DST_OFFSET);
		cal.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
		return cal.getTimeInMillis();
	}

	private LocationClient getBaiduLocationClient() {
		if (mLocationClient == null) {
			mLocationClient = ((BaseApplicationWithMapService) ((Activity) context)
					.getApplication()).getbLocationClient();
		}
		return mLocationClient;
	}

	/**
	 * @return
	 */
	public Location getLocationByBaiduAPI(long duration) {
		if(duration <=0){
			duration= 10000 ;
		}
		location = null;
		LocationClient client = new LocationClient(context);
		client.registerLocationListener(baiduLocationListener);
		client.start();
		long start = System.currentTimeMillis();
		while (System.currentTimeMillis() - start < duration && location == null) {
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return location;
	}

	public Location getLocationByBaiduLocApi(boolean gpsFirst,long duration) {
		return getLocationByBaiduLocApi(gpsFirst, duration, false);
	}
	
	public Location getLocationByBaiduLocApi(boolean gpsFirst,long duration, final boolean attchAddrInfo) {
		if(duration <=0){
			duration= 10000 ;
		}
		location = null;
		final BaseApplicationWithMapService app =
		        ((BaseApplicationWithMapService) ((Activity) context).getApplication());
		
		LocationClientOption option = new LocationClientOption();
		option.setOpenGps(true);
		option.setCoorType(LOACTION_TYPE_BAIDU);
        option.setIsNeedAddress(true);
		app.getbLocationClient().setLocOption(option);
		
		app.setLocationChangerListener(new OnLocationChangeListener() {
			@Override
			public void onGetLocation(BDLocation mlocation) {
				location = new Location(LocationManager.NETWORK_PROVIDER);
				location.setLatitude(mlocation.getLatitude());
				location.setLongitude(mlocation.getLongitude());
				
				if(attchAddrInfo) {
					Bundle extras = new Bundle();
					extras.putString("addr", mlocation.getAddrStr());
					extras.putString("district", mlocation.getDistrict());
					extras.putString("city", mlocation.getCity());
					location.setExtras(extras);
				}
				
				app.getbLocationClient().stop();
			}

			@Override
			public void onGetPoi(BDLocation poiLocation) {
			}
		});
		app.getbLocationClient().start();
		long start = System.currentTimeMillis();
		while (System.currentTimeMillis() - start < duration && location == null) {
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		app.getbLocationClient().stop();
		return location;
	}

	BDLocationListener baiduLocationListener = new BDLocationListener() {
        @Override
        public void onReceiveLocation(BDLocation l) {
            Location loc = new Location("GCJ20");
            loc.setLatitude(l.getLatitude());
            loc.setLongitude(l.getLongitude());
            location = loc;
        }
	};

	public Address getAddressbyLocation(Context cntext, Location location) {
		Address result = null;
		try {
			if (location != null) {
				Geocoder gc = new Geocoder(cntext, Locale.getDefault());
				// double geoLatitude=(int)gp.getLatitudeE6() / 1E6;
				// double geoLongitude=(int) gp.getLongitudeE6()/1E6;
				List<Address> lstAddress = gc.getFromLocation(
						location.getLatitude(), location.getLongitude(), 1);
				if (lstAddress.size() > 0) {
					result = lstAddress.get(0);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	public String getAddressByLocationWithString(Context cntext,
			Location location) {
		Address addr = getAddressbyLocation(cntext, location);
		StringBuffer sb = new StringBuffer();
		if (addr != null) {
			if (addr.getMaxAddressLineIndex() >= 2) {
				sb.append(addr.getAddressLine(1));
				sb.append(addr.getAddressLine(2));
			}
		}
		return sb.toString();
	}

	public interface LocationCallBack {
		public void onResult(Location location);
	}
}
